package cn.com.greatwall.system.modules.oauth2.service.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;

import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.com.greatwall.common.exception.EntityExistException;
import cn.com.greatwall.common.utils.FileUtil;
import cn.com.greatwall.common.utils.PageUtil;
import cn.com.greatwall.common.utils.QueryHelp;
import cn.com.greatwall.common.utils.RedisUtils;
import cn.com.greatwall.common.utils.ValidationUtil;
import cn.com.greatwall.system.modules.oauth2.domain.OauthClientDetails;
import cn.com.greatwall.system.modules.oauth2.repository.OauthClientDetailsRepository;
import cn.com.greatwall.system.modules.oauth2.service.OauthClientDetailsService;
import cn.com.greatwall.system.modules.oauth2.service.dto.OauthClientDetailsDto;
import cn.com.greatwall.system.modules.oauth2.service.dto.criteria.OauthClientDetailsQueryCriteria;
import cn.com.greatwall.system.modules.oauth2.service.mapstruct.OauthClientDetailsMapper;
import lombok.RequiredArgsConstructor;

/**
 * @Author herw
 * @Time 2020-10-24 16:24:04
 * @Version 1.0
 * @Description: TODO(用一句话描述该文件做什么)
 */
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "clientDetails")
public class OauthClientDetailsServiceImpl implements OauthClientDetailsService {
    private final OauthClientDetailsRepository oauthClientDetailsRepository;
    private final OauthClientDetailsMapper oauthClientDetailsMapper;
    private final RedisUtils redisUtils;
    private final PasswordEncoder passwordEncoder;

    @Override
    public Map<String, Object> queryAll(OauthClientDetailsQueryCriteria criteria, Pageable pageable) {
        Page<OauthClientDetails> page = oauthClientDetailsRepository.findAll(
                (root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder),
                pageable);
        return PageUtil.toPage(page.map(oauthClientDetailsMapper::toDto).getContent(), page.getTotalElements());
    }

    @Override
    public List<OauthClientDetailsDto> queryAll(OauthClientDetailsQueryCriteria criteria) {
        List<OauthClientDetails> list = oauthClientDetailsRepository.findAll(
                (root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder));
        return oauthClientDetailsMapper.toDto(list);
    }

    @Override
    @Cacheable(key = "'id:' + #p0")
    @Transactional(rollbackFor = Exception.class)
    public OauthClientDetailsDto findById(String id) {
        OauthClientDetails details = oauthClientDetailsRepository.findById(id).orElseGet(OauthClientDetails::new);
        ValidationUtil.isNull(details.getId(), "OauthClientDetails", "id", id);
        return oauthClientDetailsMapper.toDto(details);
    }

    @Override
    public void create(OauthClientDetails resources) {
        resources.setClientSecret(passwordEncoder.encode(resources.getClientSecret()));
        oauthClientDetailsRepository.save(resources);
    }
    
    @Override
    @CacheEvict("'id:' + #p0.id")
    @Transactional(rollbackFor = Exception.class)
    public void update(OauthClientDetails resources) {
        resources.setClientSecret(passwordEncoder.encode(resources.getClientSecret()));
        oauthClientDetailsRepository.save(resources);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Set<String> ids) {
        oauthClientDetailsRepository.deleteAllByIdIn(ids);
        // 清理缓存
        for (String id : ids) {
            delCaches(id);
        }
    }
    
    @Override
    public void download(List<OauthClientDetailsDto> clientDtos, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (OauthClientDetailsDto clientDTO : clientDtos) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("客户端ID", clientDTO.getId());
            map.put("权限", clientDTO.getScope());
            map.put("授权方式", clientDTO.getAuthorizedGrantTypes());
            map.put("回调URI方式", clientDTO.getWebServerRedirectUri());
            map.put("角色", clientDTO.getAuthorities());
            map.put("Token有效期", clientDTO.getAccessTokenValidity());
            map.put("Token刷新时间", clientDTO.getRefreshTokenValidity());
            map.put("备注", clientDTO.getAdditionalInformation());
            map.put("授权", clientDTO.getAutoapprove());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }
    
    /**
     * 缓存清理
     * 
     * @param dict
     */
    public void delCaches(String id) {
        redisUtils.del("client::id:" + id);
    }
}
